package org.example.encrypt.common;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.SqlCommandType;
import org.example.encrypt.annotations.CryptClass;
import org.example.encrypt.utils.AESUtil;
import org.example.encrypt.utils.CryptUtil;
import org.example.encrypt.utils.NumberCryptUtil;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author WeiBing
 * @Create 2024/8/12 18:19
 */
@Slf4j
@Component
public class MybatisCryptHandler {

    /**
     * 数据库表敏感字段定义
     */
    private static final Map<String, Class<?>> SENSITIVE_FIELDS = new HashMap<>();
    /**
     * 数据库敏感字段的key集合，本质就是取上面这个参数的key集合，我提取出来，不然每次要用都得再去一遍，烦
     */
    private static final Set<String> SENSITIVE_FIELD_NAMES = new HashSet<>();

    /**
     * 把数据库所有敏感字段都列在这里面
     */
    @PostConstruct
    public void init() {
        SENSITIVE_FIELDS.put("id_card", String.class);
        SENSITIVE_FIELDS.put("id_card_lower", String.class);
        SENSITIVE_FIELDS.put("id_card_upper", String.class);
        SENSITIVE_FIELDS.put("phone_number", String.class);
        SENSITIVE_FIELDS.put("data", String.class);
        SENSITIVE_FIELDS.put("identity_card_number", String.class);
        SENSITIVE_FIELDS.put("contact_name", String.class);
        SENSITIVE_FIELDS.put("contact_phone", String.class);
        SENSITIVE_FIELDS.put("bank_address", String.class);
        SENSITIVE_FIELDS.put("bank_account", String.class);
        SENSITIVE_FIELDS.put("actual_residential_address", String.class);
        SENSITIVE_FIELDS.put("employee_id_card", String.class);
        SENSITIVE_FIELDS.put("bonus_cardinal_num", BigDecimal.class);
        SENSITIVE_FIELDS.put("payable_bonus", BigDecimal.class);
        SENSITIVE_FIELDS.put("coefficient_of_performance", BigDecimal.class);
        SENSITIVE_FIELDS.put("actual_pay_bonus", BigDecimal.class);
        SENSITIVE_FIELDS.put("pre_tax_total_bonus", BigDecimal.class);
        SENSITIVE_FIELDS.put("labor_contract_salary", BigDecimal.class);
        SENSITIVE_FIELDS.put("try_period_salary", BigDecimal.class);
        SENSITIVE_FIELDS.put("phone_num", String.class);
        SENSITIVE_FIELDS.put("qy_wei_xin_phone", String.class);
        SENSITIVE_FIELDS.put("phone", String.class);
        SENSITIVE_FIELDS.put("base_salary", BigDecimal.class);
        SENSITIVE_FIELDS.put("job_salary", BigDecimal.class);
        SENSITIVE_FIELDS.put("performance_salary", BigDecimal.class);
        SENSITIVE_FIELDS.put("total_salary", BigDecimal.class);
        SENSITIVE_FIELDS.put("monthly_standard_salary", BigDecimal.class);

        // 这个name比较特殊，有些表的name要加密，有些的不加，要加的有t_employee_edit_family_info、t_employee_family、t_employee_relation.在对这些表进行操作时，必须把name换成这个名字
        SENSITIVE_FIELDS.put("familyOrRelationName", String.class);

        SENSITIVE_FIELDS.put("id_card_no", String.class);
        SENSITIVE_FIELDS.put("address", String.class);
        SENSITIVE_FIELDS.put("salary", String.class);
        SENSITIVE_FIELDS.put("probation_salary", String.class);
        SENSITIVE_FIELDS.put("birthplace", String.class);
        SENSITIVE_FIELDS.put("live_address", String.class);
        SENSITIVE_FIELDS.put("certificate_num", String.class);
        SENSITIVE_FIELDS.put("original_performance_salary", String.class);
        SENSITIVE_FIELDS.put("current_performance_salary", String.class);
        SENSITIVE_FIELDS.put("original_total_salary", String.class);
        SENSITIVE_FIELDS.put("current_total_salary", String.class);
        SENSITIVE_FIELDS.put("original_contract_salary", String.class);
        SENSITIVE_FIELDS.put("current_contract_salary", String.class);
        SENSITIVE_FIELDS.put("original_base_salary", String.class);
        SENSITIVE_FIELDS.put("original_job_salary", String.class);
        SENSITIVE_FIELDS.put("original_other_salary", String.class);
        SENSITIVE_FIELDS.put("current_base_salary", String.class);
        SENSITIVE_FIELDS.put("current_job_salary", String.class);
        SENSITIVE_FIELDS.put("current_other_salary", String.class);
        SENSITIVE_FIELDS.put("original_monthly_standard_salary", String.class);
        SENSITIVE_FIELDS.put("current_monthly_standard_salary", String.class);
        SENSITIVE_FIELDS.put("id_number", String.class);
        SENSITIVE_FIELDS.put("other_salary", BigDecimal.class);

        // 兼容一下小驼峰式的这种写法，因为自定义xml方式+map类型参数时，这个key可能是下划线式，也可能是小驼峰式
        HashMap<String, Class<?>> snakeTypeSensitiveField = new HashMap<>();
        for (Map.Entry<String, Class<?>> entry : SENSITIVE_FIELDS.entrySet()) {
            String key = entry.getKey();
            Class<?> value = entry.getValue();

            String snakeCase = CryptUtil.convertToCamelCaseIfNecessary(key);
            if (StrUtil.equals(key, snakeCase)) {
                continue;
            }
            snakeTypeSensitiveField.put(snakeCase, value);
        }
        if (MapUtil.isNotEmpty(snakeTypeSensitiveField)) {
            SENSITIVE_FIELDS.putAll(snakeTypeSensitiveField);
        }

        // 敏感字段key集合赋值
        SENSITIVE_FIELD_NAMES.addAll(SENSITIVE_FIELDS.keySet());
    }

    /**
     * 参数对外加密方法
     */
    public void parameterEncrypt (ParameterHandler handler, SqlCommandType sqlCommandType) {
        // 获取参数对象
        Object parameterObject = handler.getParameterObject();
        // 克隆一份参数对象，对克隆对象进行加密操作
        Object copyParameterObject = CryptUtil.getCopyObject(parameterObject);
        ReflectUtil.setFieldValue(handler, "parameterObject", copyParameterObject);
        // 参数加密
        encryptFieldHandler(parameterObject, copyParameterObject, sqlCommandType);
    }

    /**
     * 参数加密具体方法
     */
    private void encryptFieldHandler (Object oriParamterObject, Object parameterObject, SqlCommandType sqlCommandType) {
        if (null == parameterObject) {
            return;
        }
        if (parameterObject instanceof Map) {
            if (parameterObject instanceof MapperMethod.ParamMap) {
                MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap)parameterObject;

                // 兼容使用queryWrapper和updateWrapper进行操作数据库的情况
                // wrapper方式进行操作时，参数对象里会包含一个key为ew的参数，里面封装的就是具体的参数值
                if (paramMap.containsKey(Constants.WRAPPER)) {

                    Object wrapperObj = paramMap.get(Constants.WRAPPER);
                    AbstractWrapper abstractWrapper;

                    if (wrapperObj instanceof JSONObject) {
                        /*
                        由于这里的这个wrapperObj可能是JSONObject类型，如果直接强转的话可能会报错，所以特殊处理一下，
                        使用hutool进行json格式的字符串转为bean时，即JSONUtil.toBean("xxx", xxx.class)，如果里面存在泛型，那么得到的该属性类型就是JSONObject
                         */
                        MapperMethod.ParamMap oriParamMap = (MapperMethod.ParamMap) oriParamterObject;
                        Object oriWrapperObj = oriParamMap.get(Constants.WRAPPER);
                        Object specificWrapper = BeanUtil.toBean(wrapperObj, oriWrapperObj.getClass());

                        abstractWrapper= (AbstractWrapper)specificWrapper;
                    } else {
                        abstractWrapper = (AbstractWrapper)wrapperObj;
                    }

                    // 判断这个wrapper是queryWrapper还是updateWrapper，通过sqlCommandType来判断，我就只管增删改查4种，增不需要管、删和改归属于update类，查归属于query类
                    List<SqlCommandType> updateType = Arrays.asList(SqlCommandType.DELETE, SqlCommandType.UPDATE);
                    List<SqlCommandType> queryType = Collections.singletonList(SqlCommandType.SELECT);

                    // 获取SQL参数映射表和动态生成的SQL片段：不论是queryWrapper还是updateWrapper，一定都有这俩参数
                    Map<String, Object> paramNameValuePairs = abstractWrapper.getParamNameValuePairs();
                    String sqlSegment = abstractWrapper.getSqlSegment();

                    // 查询操作只需要管sql片段里是否包含敏感字段，也就是对应where后面的SQL片段
                    if (queryType.contains(sqlCommandType)) {
                        // 把where后面的SQL片段涉及的敏感字段的取值进行加密
                        this.handleColumnCrypt(sqlSegment, SENSITIVE_FIELD_NAMES, paramNameValuePairs);
                    } else if (updateType.contains(sqlCommandType)) {
                        // 修改操作：修改操作比查询操作多一个sqlSet需要处理，但是注意：delete操作时没有sqlSet，我说的是真正的delete哈，不是逻辑删除那个delete
                        String sqlSet = abstractWrapper.getSqlSet();
                        // 这里别想着把sqlSetParameterMap和sqlSegmentParameterMap合并，有这样一种情况：update t_user set phone = 'xxx' where phone = 'yyy'，遇到这种就鸡鸡了

                        // 对set语句中的敏感字段进行加密
                        if (StrUtil.isNotBlank(sqlSet)) {
                            this.handleColumnCrypt(sqlSet, SENSITIVE_FIELD_NAMES, paramNameValuePairs);
                        }

                        // 修改的时候还有这种情况：userService.update(user, queryWrapper);把参数和wrapper都传过来了，此时，就没有sqlSet了，只有et了，全称叫做entity
                        if (paramMap.containsKey(Constants.ENTITY)) {
                            Object entity = paramMap.get(Constants.ENTITY);

                            if (null != entity) {
                                this.handleEntityCrypt(entity);
                            }
                        }

                        // 对where语句中涉及的敏感字段进行加密
                        if (StrUtil.isNotBlank(sqlSegment)) {
                            this.handleColumnCrypt(sqlSegment, SENSITIVE_FIELD_NAMES, paramNameValuePairs);
                        }
                    } else {
                        log.error("不支持的sqlCommandType：{}", sqlCommandType);
                        return;
                    }
                } else if (paramMap.containsKey(Constants.COLUMN_MAP)) {
                    // 兼容一下低版本的mybatisplus，比如selectByMap这个，高低版本内部实现不同
                    // TODO：此外再注意一个点，说是mybatisplus在取值时会优先从additionalParameters里取，所以这里单独判断一下

                    Map<String, Object> columnMapObj = (Map<String, Object>)paramMap.get(Constants.COLUMN_MAP);
                    this.handleCustomMapType(columnMapObj);
                } else if (paramMap.containsKey(Constants.ENTITY)) {
                    // updateById的时候就会走这个
                    Object paramObject = paramMap.get(Constants.ENTITY);
                    if (null != paramObject) {
                        this.handleEntityCrypt(paramObject);
                    }
                } else if (paramMap.containsKey(Constants.COLLECTION)) {
                    Object o = paramMap.get(Constants.COLLECTION);
                    for (Object object : (List<?>) o) {
                        encryptFieldHandler(oriParamterObject, object, sqlCommandType);
                    }
                } else {
                    /*
                    否则就是以下形式了
                    自定义的insert方法：Integer myInsertForTest(@Param("info") EmployeeCsFamilyInfo info);
                     */

                    // 遍历parameterObject里的参数（注意：过滤一下哈，存在不同名，但是值相同的），而且，这个参数名我只要自定义的那个参数名，不要MP生成的param1,arg1这种叫法
                    HashMap<String, Object> myParamMap = new HashMap<>();
                    Set keySet = new HashSet<>(paramMap.keySet());


                    for (Object key : keySet) {
                        if (String.valueOf(key).startsWith("param") || String.valueOf(key).startsWith("arg")) {
                            continue;
                        }

                        Object value = paramMap.get(key);
                        if (myParamMap.containsValue(value)) {
                            continue;
                        }
                        myParamMap.put(String.valueOf(key), value);
                    }

                    // 经过上面的步骤，就把parameterObject去重了,且保证了key选择的是我们自己定义的参数名称
                    if (CollUtil.isNotEmpty(myParamMap)) {
                        /*
                        针对这个场景，我只支持2种情况：①元素类型是类对象类型或map类型的；②元素类型是基本类型的
                        Integer insertBatchForTest(@Param("list") List<EmployeeCsFamilyInfo> list);
                        Integer insertBatchWithMapForTest(@Param("list") List<HashMap<String, Object>> maps);
                         */
                        for (Map.Entry<String, Object> entry : myParamMap.entrySet()) {
                            String key = entry.getKey();
                            Object value = entry.getValue();

                            if (null == value) {
                                continue;
                            }

                            if (value instanceof List) {
                                List<?> list = (List<?>) value;
                                if (CollUtil.isEmpty(list)) {
                                    continue;
                                }
                                Object o1 = list.get(0);
                                Class<?> aClass = o1.getClass();
                                boolean classAnnotationPresent = aClass.isAnnotationPresent(CryptClass.class);
                                if (classAnnotationPresent) {
                                    for (Object o : list) {
                                        // list里的元素是类对象类型
                                        // 以后如果发现list类型的元素在代码里也复用了，你们你就在这再copy一份吧，我不改了
                                        this.handleEntityCrypt(o);
                                    }
                                } else {
                                    if (o1 instanceof Map) {
                                        for (Object o : list) {
                                            // list里的元素是map类型
                                            Map<String, Object> map = (Map<String, Object>) o;
                                            this.handleCustomMapType(map);
                                        }
                                    } else {
                                        log.error("不支持的加密类型");
                                    }
                                }
                            } else {
                                Class<?> aClass = value.getClass();
                                boolean annotationPresent = aClass.isAnnotationPresent(CryptClass.class);
                                if (annotationPresent) {
                                    /*
                                    自定义的单体insert方法就走这个逻辑，比如：employeeBaseInfoMapper.insertEmployeeBaseInfo(model);
                                     */
                                    this.handleEntityCrypt(value);
                                } else {
                                    // 分散参数形式，必须使用@Param注解设置别名，否则使用默认的参数名是arg0,param0这种，我判断不了他是不是敏感字段！！！切记，而且，我只支持参数是基本数据类型的，不然他妈的又套娃，难顶的很
                                    if (SENSITIVE_FIELDS.containsKey(key)) {
                                        if (value instanceof String) {
                                            String encrypt = AESUtil.encrypt(String.valueOf(value));
                                            paramMap.put(key, encrypt);
                                        } else if (value instanceof BigDecimal) {
                                            BigDecimal numberValue = (BigDecimal) value;
                                            BigDecimal encrypt = NumberCryptUtil.encrypt(numberValue);
                                            paramMap.put(key, encrypt);
                                        } else if (value instanceof Integer) {
                                            Integer numberValue = (Integer) value;
                                            BigDecimal encrypt = NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue));
                                            paramMap.put(key, encrypt);
                                        } else if (value instanceof Double) {
                                            Double numberValue = (Double) value;
                                            BigDecimal encrypt = NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue));
                                            paramMap.put(key, encrypt);
                                        } else {
                                            log.error("不支持的加密类型");
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // 目前也支持自定义的支持page分页查询的写法，比如：queryWithPage(page, User)；
                }
            } else {
                /*
                否则就是自己定义的参数map了，就不是框架自己封装的MapperMethod$ParamMap类型了，或者是分散参数的那种形式
                Integer myInsertWithMapForTest(HashMap<String, Object> paramMap);
                 */
                Map<String, Object> map = (Map<String, Object>) parameterObject;
                this.handleCustomMapType(map);
            }
            return;
        }
        if (parameterObject instanceof List) {
            // 目前好像没遇到过这种情况，有日志遇到时再说吧
            ((List<?>) parameterObject).forEach(x -> encryptFieldHandler(oriParamterObject, x, null));
            return;
        }

        /*
        parameterObject直接是类对象的情形
        service层save方法、mapper层insert方法、service层的saveBatch方法
         */
        Class<?> clazz = parameterObject.getClass();
        if (!clazz.isAnnotationPresent(CryptClass.class)) {
            return;
        }

        this.handleEntityCrypt(parameterObject);
    }

    /**
     * 处理自定义的map类型参数
     */
    public void handleCustomMapType(Map paramMap) {
        for (Object entry : paramMap.entrySet()) {
            Map.Entry<String, ?> e = (Map.Entry<String, ?>) entry;
            String key = e.getKey();
            Object value = e.getValue();
            if (null == value) {
                continue;
            }
            if (SENSITIVE_FIELDS.containsKey(key)) {
                Class<?> columnJavaType = SENSITIVE_FIELDS.get(key);
                if (columnJavaType.equals(String.class)) {
                    paramMap.put(key, AESUtil.encrypt(String.valueOf(value)));
                } else if (columnJavaType.equals(BigDecimal.class)) {
                    BigDecimal numberValue = (BigDecimal) value;
                    paramMap.put(key, NumberCryptUtil.encrypt(numberValue));
                } else if (columnJavaType.equals(Integer.class)) {
                    Integer numberValue = (Integer) value;
                    paramMap.put(key, NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue)));
                } else if (columnJavaType.equals(Double.class)) {
                    Double numberValue = (Double) value;
                    paramMap.put(key, NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue)));
                } else {
                    log.error("暂不支持的加密类型，columnJavaType:{}", columnJavaType.getName());
                }
            }
        }
    }

    /**
     * 处理参数是类对象是的敏感字段加密
     */
    private void handleEntityCrypt(Object entity) {
        try {
            Class<?> entityJavaType = entity.getClass();
            if (!entityJavaType.isAnnotationPresent(CryptClass.class)) {
                return;
            }
            // 兼容参数model对象的继承
            Field[] allFields = CryptUtil.getAllFields(entityJavaType);
//            Field[] declaredFields = entityJavaType.getDeclaredFields();
            // 获取满足加密注解条件的字段
            final List<Field> collect = Arrays.stream(allFields).filter(CryptUtil::checkEncrypt).collect(Collectors.toList());
            for (Field item : collect) {
                item.setAccessible(true);
                Object value = item.get(entity);
                if (value != null) {
                    // 判断待加密的字段所属类型，目前仅支持2类类型：①字符串类型---才有AES加密；②数值类型---采用XOR加密
                    if (value instanceof String) {
                        item.set(entity, AESUtil.encrypt((String)value));
                    } else if (value instanceof BigDecimal) {
                        BigDecimal numberValue = (BigDecimal) value;
                        item.set(entity, NumberCryptUtil.encrypt(numberValue));
                    } else if (value instanceof Integer) {
                        Integer numberValue = (Integer) value;
                        item.set(entity, NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue)));
                    } else if (value instanceof Double) {
                        Double numberValue = (Double) value;
                        item.set(entity, NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue)));
                    } else {
                        log.error("暂不支持的加密字段类型：{}", value.getClass().getName());
                    }
                }
            }
        } catch (Exception e) {
            log.error("handleEntityCrypt执行失败", e);
        }
    }

    /**
     * 判断SQL语句中是否涉及敏感字段的设值，如果涉及，那么对parameterObject里的paramNameValuePairs里对应的值进行加密
     */
    private void handleColumnCrypt(String sql, Set<String> sensitiveFieldNames, Map<String, Object> paramNameValuePairs) {
        // 提取sql中精确匹配的字段和字段取值的映射表
        Map<String, List<String>> columnNamdAndValuePathMap = CryptUtil.extractParamsToPlaceholders(sql, sensitiveFieldNames);

        if (MapUtil.isNotEmpty(columnNamdAndValuePathMap)) {
            for (Map.Entry<String, List<String>> entry : columnNamdAndValuePathMap.entrySet()) {
                String columnName = entry.getKey();
                List<String> valueList = entry.getValue();

                // 判断该字段是否是敏感字段
                if (sensitiveFieldNames.contains(columnName)) {
                    // 根据字段的类型做对应的加密
                    Class<?> columnJavaType = SENSITIVE_FIELDS.get(columnName);

                    for (String value : valueList) {
                        if (StrUtil.isBlank(value)) {
                            log.error("获取到的字段取值名称为空，当前SQL为：{}，字段为：{}", sql, columnName);
                            continue;
                        }
                        Object originalValue = paramNameValuePairs.get(value);
                        if (columnJavaType.equals(String.class)) {
                            paramNameValuePairs.put(value, AESUtil.encrypt(String.valueOf(originalValue)));
                        } else if (columnJavaType.equals(BigDecimal.class)){
                            BigDecimal numberValue = (BigDecimal) originalValue;
                            paramNameValuePairs.put(value, NumberCryptUtil.encrypt(numberValue));
                        } else if (columnJavaType.equals(Integer.class)) {
                            Integer numberValue = (Integer) originalValue;
                            paramNameValuePairs.put(value, NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue)));
                        } else if (columnJavaType.equals(Double.class)) {
                            Double numberValue = (Double) originalValue;
                            paramNameValuePairs.put(value, NumberCryptUtil.encrypt(BigDecimal.valueOf(numberValue)));
                        } else {
                            log.error("符合敏感字段定义，但是暂不支持的加密类型:{}", columnJavaType.getName());
                        }
                    }
                }
            }
        }
    }

    /**
     * 查询结果对外解密方法
     */
    public Object resultDecrypt (Object resultData) {
        if (null == resultData) {
            return null;
        }
        if (resultData instanceof List) {
            // 返回多条数据，2种情况：①元素是类对象；②元素是map类型
            List<?> resultDataList = (List<?>) resultData;
            if (CollUtil.isEmpty(resultDataList)) {
                return resultData;
            }
            return ((List<?>) resultData).stream().map(this::resultObjHandler).collect(Collectors.toList());
        } else {
            // 返回单条数据，也是2种情况：①类对象类型；②map类型
            return resultObjHandler(resultData);
        }
    }

    /**
     * 查询结果具体解密方法
     */
    private Object resultObjHandler (Object result) {
        if (null == result) {
            return null;
        }

        // 判断是类对象类型还是map类型
        if (result instanceof Map) {
            // 遍历map里的字段，对敏感字段进行解密
            Set<String> sensitiveFields = SENSITIVE_FIELDS.keySet();
            Map<String, Object> resultMap = (Map<String, Object>) result;
            for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();

                if (sensitiveFields.contains(key)) {
                    if (null == value) {
                        continue;
                    }
                    if (value instanceof String) {
                        resultMap.put(key, AESUtil.decrypt((String)value));
                    } else if (value instanceof BigDecimal) {
                        BigDecimal numberValue = (BigDecimal) value;
                        resultMap.put(key, NumberCryptUtil.decrypt(numberValue));
                    } else if (value instanceof Integer) {
                        Integer numberValue = (Integer) value;
                        resultMap.put(key, NumberCryptUtil.decrypt(BigDecimal.valueOf(numberValue)));
                    } else if (value instanceof Double) {
                        Double numberValue = (Double) value;
                        resultMap.put(key, NumberCryptUtil.decrypt(BigDecimal.valueOf(numberValue)));
                    } else {
                        log.error("暂不支持的解密字段类型：{}", value.getClass().getName());
                    }
                }
            }
        } else {
            // 否则就是单体对象类型了或者是基本数据类型了，比如你只查一个值
            Class<?> clazz = result.getClass();
            boolean classAnnotationPresent = clazz.isAnnotationPresent(CryptClass.class);
            if (classAnnotationPresent) {
                //获取所有要解密的字段，兼容一下model对象的继承
//                Field[] declaredFields = clazz.getDeclaredFields();
                Field[] allFields = CryptUtil.getAllFields(clazz);
                List<Field> collect = Arrays.stream(allFields).filter(CryptUtil::checkDecrypt).collect(Collectors.toList());
                for (Field item : collect) {
                    try {
                        item.setAccessible(true);
                        Object value = item.get(result);
                        // 如果字段的值是null，那直接跳过
                        if (null == value) {
                            continue;
                        }
                        if (value instanceof String) {
                            item.set(result, AESUtil.decrypt((String)value));
                        } else if (value instanceof BigDecimal) {
                            BigDecimal numberValue = (BigDecimal) value;
                            item.set(result, NumberCryptUtil.decrypt(numberValue));
                        } else if (value instanceof Integer) {
                            Integer numberValue = (Integer) value;
                            item.set(result, NumberCryptUtil.decrypt(BigDecimal.valueOf(numberValue)));
                        } else if (value instanceof Double) {
                            Double numberValue = (Double) value;
                            item.set(result, NumberCryptUtil.decrypt(BigDecimal.valueOf(numberValue)));
                        } else {
                            log.error("暂不支持的解密字段类型：{}", value.getClass().getName());
                        }
                    } catch (Exception e) {
                        log.error("查询结果解密存在失败：\n", e);
                    }
                }

                collect.stream().filter(CryptUtil::checkSubObject).forEach(item -> {
                    try {
                        item.setAccessible(true);
                        Object data = item.get(result);
                        if (data instanceof List) {
                            ((List<?>) data).forEach(this::resultObjHandler);
                        }
                    } catch (IllegalAccessException e) {
                        log.error("查询结果解密存在失败：\n", e);
                    }
                });
            } else {
                // 否则我就认为是基本类型了，但是，我他喵只能拿到值啊，拿不到这个值是哪个字段的值啊，也就是不知道字段名，压根没法处理
                // 顺便补充个知识点，单值查询时，返回的result是一个list类型的
//                log.error("不支持的解密对象，可能是单值查询，目前不支持单值查询解密");
            }
        }

        return result;
    }


}
